package com.rupertjones.globalcron.common.scheduling;

import com.rupertjones.globalcron.common.domain.JobDescriptor;
import org.apache.log4j.Logger;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.StatefulJob;
import org.springframework.scheduling.quartz.QuartzJobBean;

import static java.lang.String.format;

public class QuartzJob extends QuartzJobBean implements StatefulJob {
    private JobExecutionContext context;
    private JobDescriptor jobDescriptor;
    private static final Logger LOG = Logger.getLogger(QuartzJob.class);
    private JobExecutionListener listener;

    public void setJobDescriptor(JobDescriptor jobDescriptor) {
        this.jobDescriptor = jobDescriptor;
    }

    public void setJobExecutionListener(JobExecutionListener listener) {
        this.listener = listener;
    }

    public JobDescriptor getJobDescriptor() {
        return jobDescriptor;
    }

    public String getSummary() {
        return format("[id: %s] [name: %s] [cron: %s @ %s] [enabled: %s] host: [%s]",
                jobDescriptor.getId(), jobDescriptor.getName(), jobDescriptor.getCron(),
                jobDescriptor.getTimezone(), jobDescriptor.isEnabled(), jobDescriptor.getHost().getSummary());
    }

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        long start = 0;
        long end = 0;
        Executable runnable = jobDescriptor.getRunnable();

        if (jobDescriptor.canRun())  {
            LOG.info("Executing: " + getSummary());
            start = System.currentTimeMillis();
            runnable.run();
            end = System.currentTimeMillis();
            long timeTaken = (end - start);
            String message = format("Completed Executing: %s in %s ms, Next Fire Time: %s", getSummary(), timeTaken, context.getNextFireTime());
            LOG.info(message);
            ExecutionContext executionContext = new ExecutionContext();
            executionContext.setJobDescriptor(jobDescriptor);
            executionContext.setTimeTaken(timeTaken);
            executionContext.setExecutedNormally(runnable.executedNormally());
            executionContext.setOutput(runnable.getOutput());
            executionContext.setSummary(message);
            executionContext.setNextFire(context.getNextFireTime());
            executionContext.setLastFire(context.getFireTime());
            afterExecution(executionContext);
        } else {
            LOG.debug(format("Job triggered, but script not executing [%s]", getSummary()));
        }
    }

    private void afterExecution(ExecutionContext executionContext) {
        if (listener != null) {
            listener.afterExecution(executionContext);
        }
    }
}
